#include <zmq.h>
#include <stdio.h>
#include <string.h>

typedef enum
{
    PCIE_SET         = 1,
    PCIE_GET         = 2,
    PCIE_SETS        = 3,
    PCIE_GETS        = 4,
    PCIE_READMEM     = 5,
    PCIE_WRITEMEM    = 6,
}fa_pcie_op_e;

//#define COMM_URL "tcp://127.0.0.1:5555"
#define COMM_URL "inproc://lat_test"

void dump_msg(const void* data, int size)
{
    unsigned char* ptr = (unsigned char*)data;
    printf("[%03d] ", size);
    int i = 0;
    for (i = 0; i < size; i++)
        printf("%02X", ptr[i]);
    //printf("%.*s\r\n", size, ptr);
}

void dump_addressX(const char* header, const void* data, int size)
{
    unsigned char* ptr = (unsigned char*)data;
    printf("[%s %03d] ", header, size);
    int i = 0;
    for (i = 0; i < size; i++)
        printf("%02X", ptr[i]);

    printf("\n");
}

typedef struct fa_pcie_req
{
    fa_pcie_op_e        op;
    uint32_t            number;
    uint32_t            addr_offset;
    uint32_t            value[64];
}fa_pcie_req_t, fa_pcie_rep_t;

int fa_pcie_set_reg(void* fd, uint32_t op, uint32_t offset, uint32_t value)
{
    fa_pcie_req_t req = { (fa_pcie_op_e)op , offset, value};

    //dump_addressX("send", (const void *)&req, sizeof(fa_pcie_req_t));
    int len = zmq_send(fd, (void *)&req, sizeof(fa_pcie_req_t), 0);
    return len;
}

int fa_pcie_get_reg(void* fd, fa_pcie_req_t *req, fa_pcie_rep_t *rep)
{
    char buf[256] = {0};
    //dump_addressX("send", (const void *)&req, sizeof(fa_pcie_req_t));
    int len = zmq_send(fd, (void*)req, sizeof(fa_pcie_req_t), 0);
    int ret = zmq_recv(fd, buf, sizeof(buf), 0);
    *rep = *(fa_pcie_rep_t *)buf;
    return len;
}

void fa_pcie_recv_msg(void* fd, zmq_msg_t *fromaddr, void *data, uint32_t size)
{
    fa_pcie_req_t *req = (fa_pcie_req_t *)data;
    
    if ((uint32_t)req->op == (uint32_t)PCIE_SET) {
        //dump_addressX("recv", data, size);
    }
}

void fa_pcie_recv_msg2(void* fd)
{
    zmq_msg_t address;
    zmq_msg_t data;
    int ret;

    zmq_msg_init(&address);
    zmq_msg_init(&data);
    /*接收到的第一帧表示对端的地址*/
    ret = zmq_msg_recv(&address, fd, 0);
    //dump_address(zmq_msg_data(&address), ret);

    /*从第二帧开始才是对端发来的消息*/
    ret = zmq_msg_recv(&data, fd, 0);

    fa_pcie_recv_msg(fd, &address, zmq_msg_data(&data), ret);
}

void dump_address(const void* data, int size)
{
    unsigned char* ptr = (unsigned char*)data;
    printf("[%03d] ", size);
    int i = 0;
    //for (i = 0; i < size; i++)
    //    printf("%02X", ptr[i]);
    
    printf("%.*s\r\n", size, ptr);
    printf("\n");
}

void* watch;

void dealer_main(void* arg)
{
    //void* context = zmq_ctx_new();
    void* context = arg;
    void* dealer = zmq_socket(context, ZMQ_DEALER);
    zmq_setsockopt(dealer, ZMQ_ROUTING_ID, "S100", 4);

    zmq_connect(dealer, COMM_URL);

    int ret;
    char buf[256] = "hello";
    int total = 10000;
    //void* watch;
    
    watch = zmq_stopwatch_start();
    while (total)
    {
        //strcpy(buf, "hello");
        /*发送一帧，不需要发送地址帧*/
        //zmq_send(dealer, buf, strlen(buf), 0);
        fa_pcie_set_reg(dealer, PCIE_SET, 0, 1);
        fa_pcie_set_reg(dealer, PCIE_SET, 0, 1);
        fa_pcie_set_reg(dealer, PCIE_SET, 0, 1);
        fa_pcie_req_t req = {1,2,3};
        fa_pcie_rep_t rep = {0,0,0};
        //fa_pcie_get_reg(dealer, &req, &rep);

        //zmq_sleep(1);
        /*接收一帧，不会接收到地址帧*/
        //ret = zmq_recv(dealer, buf, sizeof(buf), 0);
        //dump_msg(buf, ret);
        total--;
    }
    //unsigned long usconsume = zmq_stopwatch_stop(watch);
    //printf("time consumed %ld\r\n", usconsume);
    zmq_sleep(1);
    zmq_close(dealer);
    zmq_ctx_destroy(context);
}

int main(void)
{
    void* context = zmq_ctx_new();
    void* router = zmq_socket(context, ZMQ_ROUTER);
    //zmq_bind(router, "tcp://*:5555");
    zmq_bind(router, COMM_URL);

    zmq_threadstart(dealer_main, context);

    int ret;
    zmq_msg_t address;
    zmq_msg_t data;
    while (1)
    {
        //zmq_msg_init(&address);
        //zmq_msg_init(&data);
        ///*接收到的第一帧表示对端的地址*/
        //ret = zmq_msg_recv(&address, router, 0);
        ////dump_address(zmq_msg_data(&address), ret);

        ///*从第二帧开始才是对端发来的消息*/
        //ret = zmq_msg_recv(&data, router, 0);
        ////dump_msg(zmq_msg_data(&data), ret);
        //fa_pcie_recv_msg(router, &address, zmq_msg_data(&data), ret);
        fa_pcie_recv_msg2(router);
        fa_pcie_recv_msg2(router);
        fa_pcie_recv_msg2(router);
        unsigned long usconsume = zmq_stopwatch_stop(watch);
        printf("time consumed %ld\r\n", usconsume);



        /*发送的时候，先发一帧对端的地址*/
        zmq_msg_send(&address, router, ZMQ_SNDMORE);
        /*然后再发送给对端消息*/
        //memcpy(zmq_msg_data(&data), "world", strlen("world"));
        zmq_msg_send(&data, router, 0);

        zmq_msg_close(&address);
        zmq_msg_close(&data);
    }
    zmq_close(router);
    zmq_ctx_destroy(context);
    return 0;
}